https://fedorahosted.org/freeipa/ticket/4925

I had to use ldif parser to edit DSE file instead (patch 236) and due to cyclic import caused by upgrade instace and dsintance I had to move realm_to_serverid from dsinstance to installutils.

Patches attached.

--
Martin Basti

From 4c89978091fdec7bd30a58fe26bef1070269231f Mon Sep 17 00:00:00 2001
From: Martin Basti <mba...@redhat.com>
Date: Mon, 27 Apr 2015 14:42:31 +0200
Subject: [PATCH 1/3] move realm_to_serverid to installutils module

To avoid cyclic imports realm_to_serverid function had to be moved to
installutils from dsinstance.

Required for: https://fedorahosted.org/freeipa/ticket/4925
---
 install/tools/ipa-ca-install                |  2 +-
 install/tools/ipa-replica-install           |  3 ++-
 install/tools/ipa-server-install            |  8 +++++---
 install/tools/ipa-upgradeconfig             |  6 +++---
 install/tools/ipactl                        |  4 ++--
 ipaserver/install/adtrustinstance.py        |  3 +--
 ipaserver/install/bindinstance.py           |  3 +--
 ipaserver/install/cainstance.py             |  2 +-
 ipaserver/install/dsinstance.py             |  9 +++------
 ipaserver/install/installutils.py           |  3 +++
 ipaserver/install/ipa_backup.py             | 19 ++++++++++++-------
 ipaserver/install/ipa_replica_prepare.py    |  2 +-
 ipaserver/install/ipa_restore.py            |  9 +++++----
 ipaserver/install/ipa_server_certinstall.py |  2 +-
 ipaserver/install/krbinstance.py            |  2 +-
 ipaserver/install/upgradeinstance.py        |  3 +--
 16 files changed, 43 insertions(+), 37 deletions(-)

diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install
index 6f8ff880b5d152197000f3c03f7e7b90f9945da0..f087d2d6a5138915008395cde4c461fc7602811b 100755
--- a/install/tools/ipa-ca-install
+++ b/install/tools/ipa-ca-install
@@ -284,7 +284,7 @@ def install_master(safe_options, options):
         check_ca()
 
     dirname = dsinstance.config_dirname(
-        dsinstance.realm_to_serverid(realm_name))
+        installutils.realm_to_serverid(realm_name))
     cadb = certs.CertDB(realm_name, subject_base=subject_base)
     dsdb = certs.CertDB(realm_name, nssdir=dirname, subject_base=subject_base)
 
diff --git a/install/tools/ipa-replica-install b/install/tools/ipa-replica-install
index 86931293fef247ea696eb1f821f287a03188da2d..b09a5f16e7cfe49337d88add5e20372f3a87031b 100755
--- a/install/tools/ipa-replica-install
+++ b/install/tools/ipa-replica-install
@@ -544,7 +544,8 @@ def main():
         fd.write("realm=%s\n" % config.realm_name)
         fd.write("domain=%s\n" % config.domain_name)
         fd.write("xmlrpc_uri=https://%s/ipa/xml\n"; % ipautil.format_netloc(config.host_name))
-        fd.write("ldap_uri=ldapi://%%2fvar%%2frun%%2fslapd-%s.socket\n" % dsinstance.realm_to_serverid(config.realm_name))
+        fd.write("ldap_uri=ldapi://%%2fvar%%2frun%%2fslapd-%s.socket\n" %
+                 installutils.realm_to_serverid(config.realm_name))
         if ipautil.file_exists(config.dir + "/cacert.p12"):
             fd.write("enable_ra=True\n")
             fd.write("ra_plugin=dogtag\n")
diff --git a/install/tools/ipa-server-install b/install/tools/ipa-server-install
index 56a43770d95387762bce09634bd1056ba7f20576..1fe5bd9ea6294a79728ed68216ea407857790d34 100755
--- a/install/tools/ipa-server-install
+++ b/install/tools/ipa-server-install
@@ -655,7 +655,8 @@ def uninstall():
                           'mean your system hasn\'t be restored to its pre-installation state.' % SYSRESTORE_DIR_PATH)
 
     # Note that this name will be wrong after the first uninstall.
-    dirname = dsinstance.config_dirname(dsinstance.realm_to_serverid(api.env.realm))
+    dirname = dsinstance.config_dirname(
+        installutils.realm_to_serverid(api.env.realm))
     dirs = [dirname, dogtag_constants.ALIAS_DIR, certs.NSS_DIR]
     ids = certmonger.check_state(dirs)
     if ids:
@@ -666,7 +667,7 @@ def uninstall():
 
 def set_subject_in_config(realm_name, dm_password, suffix, subject_base):
         ldapuri = 'ldapi://%%2fvar%%2frun%%2fslapd-%s.socket' % (
-            dsinstance.realm_to_serverid(realm_name)
+            installutils.realm_to_serverid(realm_name)
         )
         try:
             conn = ldap2(shared_instance=False, ldap_uri=ldapuri, base_dn=suffix)
@@ -1134,7 +1135,8 @@ def main():
     fd.write("realm=%s\n" % realm_name)
     fd.write("domain=%s\n" % domain_name)
     fd.write("xmlrpc_uri=https://%s/ipa/xml\n"; % format_netloc(host_name))
-    fd.write("ldap_uri=ldapi://%%2fvar%%2frun%%2fslapd-%s.socket\n" % dsinstance.realm_to_serverid(realm_name))
+    fd.write("ldap_uri=ldapi://%%2fvar%%2frun%%2fslapd-%s.socket\n" %
+             installutils.realm_to_serverid(realm_name))
     if setup_ca:
         fd.write("enable_ra=True\n")
         fd.write("ra_plugin=dogtag\n")
diff --git a/install/tools/ipa-upgradeconfig b/install/tools/ipa-upgradeconfig
index 8159ce244b873962df36409b884bc3ee70621f2f..dfef1e0aa8b1507b7aa4907e9b688ce99253b87c 100755
--- a/install/tools/ipa-upgradeconfig
+++ b/install/tools/ipa-upgradeconfig
@@ -1132,7 +1132,7 @@ def fix_schema_file_syntax():
         root_logger.info('Syntax already fixed')
         return
 
-    serverid = dsinstance.realm_to_serverid(api.env.realm)
+    serverid = installutils.realm_to_serverid(api.env.realm)
     ds_dir = dsinstance.config_dirname(serverid)
 
     # 1. 60ipadns.ldif: Add parenthesis to idnsRecord
@@ -1191,7 +1191,7 @@ def remove_ds_ra_cert(subject_base):
         return
 
     dbdir = dsinstance.config_dirname(
-        dsinstance.realm_to_serverid(api.env.realm))
+        installutils.realm_to_serverid(api.env.realm))
     dsdb = certs.CertDB(api.env.realm, nssdir=dbdir, subject_base=subject_base)
 
     nickname = 'CN=IPA RA,%s' % subject_base
@@ -1309,7 +1309,7 @@ def main():
                     'ca.crl.MasterCRL.enableCRLUpdates', '=')
             sub_dict['CLONE']='#' if crl.lower() == 'true' else ''
 
-        ds_serverid = dsinstance.realm_to_serverid(api.env.realm)
+        ds_serverid = installutils.realm_to_serverid(api.env.realm)
         ds_dirname = dsinstance.config_dirname(ds_serverid)
 
         upgrade(sub_dict, paths.HTTPD_IPA_CONF, ipautil.SHARE_DIR + "ipa.conf")
diff --git a/install/tools/ipactl b/install/tools/ipactl
index f3253e3f667b449e1df523eaa5e55cb33f43b467..4f3bfb16cc15877b6a34fca9ddc4dd4a9bbb9ff4 100755
--- a/install/tools/ipactl
+++ b/install/tools/ipactl
@@ -25,7 +25,7 @@ import json
 import ldapurl
 
 from ipaserver.install import service, installutils
-from ipaserver.install.dsinstance import config_dirname, realm_to_serverid
+from ipaserver.install.dsinstance import config_dirname
 from ipaserver.install.installutils import is_ipa_configured, ScriptError
 from ipalib import api, errors
 from ipapython.ipaldap import IPAdmin
@@ -53,7 +53,7 @@ def is_dirsrv_debugging_enabled():
     returns True or False
     """
     debugging = False
-    serverid = realm_to_serverid(api.env.realm)
+    serverid = installutils.realm_to_serverid(api.env.realm)
     dselist = [config_dirname(serverid)]
     for dse in dselist:
         try:
diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py
index b4d644fdbf784dd7936adc8eb085f4825cab797e..5fef66112ef91733186758c270a60fe15e1083cd 100644
--- a/ipaserver/install/adtrustinstance.py
+++ b/ipaserver/install/adtrustinstance.py
@@ -28,7 +28,6 @@ import re
 
 from ipaserver.install import service
 from ipaserver.install import installutils
-from ipaserver.install.dsinstance import realm_to_serverid
 from ipaserver.install.bindinstance import get_rr, add_rr, del_rr, \
                                            dns_zone_exists
 from ipalib import errors, api
@@ -156,7 +155,7 @@ class ADTRUSTInstance(service.Service):
         self.cifs_principal = "cifs/" + self.fqdn + "@" + self.realm
         self.suffix = ipautil.realm_to_suffix(self.realm)
         self.ldapi_socket = "%%2fvar%%2frun%%2fslapd-%s.socket" % \
-                            realm_to_serverid(self.realm)
+                            installutils.realm_to_serverid(self.realm)
 
         # DN definitions
         self.trust_dn = DN(api.env.container_trusts, self.suffix)
diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py
index 773322831b50ac189fab5ceb22eab870cecdffe8..d26e7e4210f5438abb8b840234d89277b6decf15 100644
--- a/ipaserver/install/bindinstance.py
+++ b/ipaserver/install/bindinstance.py
@@ -30,7 +30,6 @@ import ldap
 import installutils
 import service
 from ipaserver.plugins import ldap2
-from ipaserver.install.dsinstance import realm_to_serverid
 from ipaserver.install.cainstance import IPA_CA_RECORD
 from ipapython import sysrestore, ipautil, ipaldap
 from ipapython.ipa_log_manager import *
@@ -737,7 +736,7 @@ class BindInstance(service.Service):
             DOMAIN=self.domain,
             HOST=self.host,
             REALM=self.realm,
-            SERVER_ID=realm_to_serverid(self.realm),
+            SERVER_ID=installutils.realm_to_serverid(self.realm),
             FORWARDERS=fwds,
             SUFFIX=self.suffix,
             OPTIONAL_NTP=optional_ntp,
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index 8ccfd1a822fab557dc1b6bf6d0e7de3ef495efbb..7ba992bef7861d3c964df728ecc64adc958ade61 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -1771,7 +1771,7 @@ def update_people_entry(dercert):
     issuer = x509.get_issuer(dercert, datatype=x509.DER)
 
     attempts = 0
-    server_id = dsinstance.realm_to_serverid(api.env.realm)
+    server_id = installutils.realm_to_serverid(api.env.realm)
     dogtag_uri = 'ldapi://%%2fvar%%2frun%%2fslapd-%s.socket' % server_id
     updated = False
 
diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py
index da00bcf8236fb07fdf46019a196e8aab8cfb9f1d..52df6b7dea218669f9f89a7f6ae65614f494368c 100644
--- a/ipaserver/install/dsinstance.py
+++ b/ipaserver/install/dsinstance.py
@@ -73,9 +73,6 @@ def find_server_root():
     else:
         return paths.USR_LIB_DIRSRV
 
-def realm_to_serverid(realm_name):
-    return "-".join(realm_name.split("."))
-
 def config_dirname(serverid):
     return (paths.ETC_DIRSRV_SLAPD_INSTANCE_TEMPLATE % serverid) + "/"
 
@@ -266,7 +263,7 @@ class DsInstance(service.Service):
     def init_info(self, realm_name, fqdn, domain_name, dm_password,
                   subject_base, idstart, idmax, pkcs12_info, ca_file=None):
         self.realm = realm_name.upper()
-        self.serverid = realm_to_serverid(self.realm)
+        self.serverid = installutils.realm_to_serverid(self.realm)
         self.suffix = ipautil.realm_to_suffix(self.realm)
         self.fqdn = fqdn
         self.dm_password = dm_password
@@ -844,7 +841,7 @@ class DsInstance(service.Service):
         # shutdown the server
         self.stop()
 
-        dirname = config_dirname(realm_to_serverid(self.realm))
+        dirname = config_dirname(installutils.realm_to_serverid(self.realm))
         certdb = certs.CertDB(self.realm, nssdir=dirname, subject_base=self.subject_base)
         if not cacert_name or len(cacert_name) == 0:
             cacert_name = "Imported CA"
@@ -981,7 +978,7 @@ class DsInstance(service.Service):
                               'certmap.conf')
 
             certmap_dir = config_dirname(
-                realm_to_serverid(api.env.realm)
+                installutils.realm_to_serverid(api.env.realm)
             )
             try:
                 with open(os.path.join(certmap_dir, 'certmap.conf')) as f:
diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py
index 8a4f2cadab89390df0363bdd9adf4c023cadfd8c..dc41c0f870ddbe61171dbf942fde89a077bdd9da 100644
--- a/ipaserver/install/installutils.py
+++ b/ipaserver/install/installutils.py
@@ -1105,3 +1105,6 @@ def check_version():
             )
     else:
         raise UpgradeMissingVersionError("no data_version stored")
+
+def realm_to_serverid(realm_name):
+    return "-".join(realm_name.split("."))
diff --git a/ipaserver/install/ipa_backup.py b/ipaserver/install/ipa_backup.py
index 9771f8ae375aa6a87855d26ccd8e9707e02eb9ad..c3611b241d4818bc718d8bcd83da8d3c1755457e 100644
--- a/ipaserver/install/ipa_backup.py
+++ b/ipaserver/install/ipa_backup.py
@@ -34,7 +34,7 @@ from ipapython.ipautil import run, write_tmp_file
 from ipapython import admintool
 from ipapython.config import IPAOptionParser
 from ipapython.dn import DN
-from ipaserver.install.dsinstance import realm_to_serverid, DS_USER
+from ipaserver.install.dsinstance import DS_USER
 from ipaserver.install.replication import wait_for_task
 from ipaserver.install import installutils
 from ipapython import ipaldap
@@ -290,7 +290,9 @@ class Backup(admintool.AdminTool):
                 self.log.info('Stopping IPA services')
                 run(['ipactl', 'stop'])
 
-            for instance in [realm_to_serverid(api.env.realm), 'PKI-IPA']:
+            for instance in [
+                installutils.realm_to_serverid(api.env.realm), 'PKI-IPA'
+            ]:
                 if os.path.exists(paths.VAR_LIB_SLAPD_INSTANCE_DIR_TEMPLATE % instance):
                     if os.path.exists(paths.SLAPD_INSTANCE_DB_DIR_TEMPLATE % (instance, 'ipaca')):
                         self.db2ldif(instance, 'ipaca', online=options.online)
@@ -323,10 +325,12 @@ class Backup(admintool.AdminTool):
         NOTE: this adds some things that may not get backed up, like the PKI-IPA
               instance.
         '''
+        serverid = installutils.realm_to_serverid(api.env.realm)
+
         for dir in [
-                paths.ETC_DIRSRV_SLAPD_INSTANCE_TEMPLATE % realm_to_serverid(api.env.realm),
-                paths.VAR_LIB_DIRSRV_INSTANCE_SCRIPTS_TEMPLATE % realm_to_serverid(api.env.realm),
-                paths.VAR_LIB_SLAPD_INSTANCE_DIR_TEMPLATE % realm_to_serverid(api.env.realm),
+                paths.ETC_DIRSRV_SLAPD_INSTANCE_TEMPLATE % serverid,
+                paths.VAR_LIB_DIRSRV_INSTANCE_SCRIPTS_TEMPLATE % serverid,
+                paths.VAR_LIB_SLAPD_INSTANCE_DIR_TEMPLATE % serverid,
                 paths.VAR_LIB_SLAPD_PKI_IPA_DIR_TEMPLATE,
                 paths.USR_LIB_SLAPD_PKI_IPA_DIR,
                 paths.ETC_SLAPD_PKI_IPA_DIR,
@@ -337,13 +341,14 @@ class Backup(admintool.AdminTool):
                 self.dirs.append(dir)
 
         for file in [
-                paths.SYSCONFIG_DIRSRV_INSTANCE % realm_to_serverid(api.env.realm),
+                paths.SYSCONFIG_DIRSRV_INSTANCE % serverid,
                 paths.SYSCONFIG_DIRSRV_PKI_IPA_DIR]:
             if os.path.exists(file):
                 self.files.append(file)
 
         for log in [
-              paths.VAR_LOG_DIRSRV_INSTANCE_TEMPLATE % realm_to_serverid(api.env.realm),]:
+            paths.VAR_LOG_DIRSRV_INSTANCE_TEMPLATE % serverid,
+        ]:
             self.logs.append(log)
 
 
diff --git a/ipaserver/install/ipa_replica_prepare.py b/ipaserver/install/ipa_replica_prepare.py
index 79fdf2f50ce41894bfb93120e8c2f6b11af675ab..a66b39d6f4bbe5102781b43e61a0f164f38081bd 100644
--- a/ipaserver/install/ipa_replica_prepare.py
+++ b/ipaserver/install/ipa_replica_prepare.py
@@ -162,7 +162,7 @@ class ReplicaPrepare(admintool.AdminTool):
             raise admintool.ScriptError("You can't create a replica on itself")
 
         config_dir = dsinstance.config_dirname(
-            dsinstance.realm_to_serverid(api.env.realm))
+            installutils.realm_to_serverid(api.env.realm))
         if not ipautil.dir_exists(config_dir):
             raise admintool.ScriptError(
                 "could not find directory instance: %s" % config_dir)
diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py
index b5caad2405087f84ed66bd11d3a504b1fd34f818..cc466c20424d14af0cfbaf250f3b4c5ca33142dd 100644
--- a/ipaserver/install/ipa_restore.py
+++ b/ipaserver/install/ipa_restore.py
@@ -32,8 +32,7 @@ from ipapython import version, ipautil, certdb, dogtag
 from ipapython.ipautil import run, user_input
 from ipapython import admintool
 from ipapython.dn import DN
-from ipaserver.install.dsinstance import (realm_to_serverid,
-                                          create_ds_user, DS_USER)
+from ipaserver.install.dsinstance import create_ds_user, DS_USER
 from ipaserver.install.cainstance import PKI_USER, create_ca_user
 from ipaserver.install.replication import (wait_for_task, ReplicationManager,
                                            get_cs_replication_manager)
@@ -791,7 +790,7 @@ class Restore(admintool.AdminTool):
         httpinstance.HTTPInstance().stop_tracking_certificates()
         try:
             dsinstance.DsInstance().stop_tracking_certificates(
-                realm_to_serverid(api.env.realm))
+                installutils.realm_to_serverid(api.env.realm))
         except OSError:
             # When IPA is not installed, DS NSS DB does not exist
             pass
@@ -832,5 +831,7 @@ class Restore(admintool.AdminTool):
         api.bootstrap(in_server=False, context='restore', **overrides)
         api.finalize()
 
-        self.instances = [realm_to_serverid(api.env.realm), 'PKI-IPA']
+        self.instances = [
+            installutils.realm_to_serverid(api.env.realm), 'PKI-IPA'
+        ]
         self.backends = ['userRoot', 'ipaca']
diff --git a/ipaserver/install/ipa_server_certinstall.py b/ipaserver/install/ipa_server_certinstall.py
index 80cf6d5d530b514e45a9e8dce4c9fcce7d4f5c57..9e24c4ce0ed69f7aeb452fc12902dfa1d4b28536 100644
--- a/ipaserver/install/ipa_server_certinstall.py
+++ b/ipaserver/install/ipa_server_certinstall.py
@@ -114,7 +114,7 @@ class ServerCertInstall(admintool.AdminTool):
         conn.disconnect()
 
     def install_dirsrv_cert(self):
-        serverid = dsinstance.realm_to_serverid(api.env.realm)
+        serverid = installutils.realm_to_serverid(api.env.realm)
         dirname = dsinstance.config_dirname(serverid)
 
         conn = api.Backend.ldap2
diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py
index 266adb33b8acdea7a40c6ed74ffa95d7ddaa8155..154dbea722903f7973c8472cc3afdb0cac1f5ed2 100644
--- a/ipaserver/install/krbinstance.py
+++ b/ipaserver/install/krbinstance.py
@@ -235,7 +235,7 @@ class KrbInstance(service.Service):
                              SUFFIX=self.suffix,
                              DOMAIN=self.domain,
                              HOST=self.host,
-                             SERVER_ID=dsinstance.realm_to_serverid(self.realm),
+                             SERVER_ID=installutils.realm_to_serverid(self.realm),
                              REALM=self.realm)
 
         # IPA server/KDC is not a subdomain of default domain
diff --git a/ipaserver/install/upgradeinstance.py b/ipaserver/install/upgradeinstance.py
index 160b735c8f567779dcb5d94cc6ae840338b9eef1..08d5e91fb41cb395b3599818d3f506374ebad2eb 100644
--- a/ipaserver/install/upgradeinstance.py
+++ b/ipaserver/install/upgradeinstance.py
@@ -26,7 +26,6 @@ from ipaplatform.paths import paths
 from ipapython.ipa_log_manager import *
 
 from ipaserver.install import installutils
-from ipaserver.install import dsinstance
 from ipaserver.install import schemaupdate
 from ipaserver.install import ldapupdate
 from ipaserver.install import service
@@ -51,7 +50,7 @@ class IPAUpgrade(service.Service):
             h = "%02x" % rand.randint(0,255)
             ext += h
         service.Service.__init__(self, "dirsrv")
-        serverid = dsinstance.realm_to_serverid(realm_name)
+        serverid = installutils.realm_to_serverid(realm_name)
         self.filename = '%s/%s' % (paths.ETC_DIRSRV_SLAPD_INSTANCE_TEMPLATE % serverid, DSE)
         self.savefilename = '%s/%s.ipa.%s' % (paths.ETC_DIRSRV_SLAPD_INSTANCE_TEMPLATE % serverid, DSE, ext)
         self.files = files
-- 
2.1.0

From 7e72d674598827a69745c044c0d7ea8a5d11511b Mon Sep 17 00:00:00 2001
From: Martin Basti <mba...@redhat.com>
Date: Tue, 28 Apr 2015 10:04:31 +0200
Subject: [PATCH 2/3] Server Upgrade: use LDIF parser to modify DSE.ldif

Ticket: https://fedorahosted.org/freeipa/ticket/4925
---
 ipaserver/install/upgradeinstance.py | 185 +++++++++++++++++++++++++++++++----
 1 file changed, 165 insertions(+), 20 deletions(-)

diff --git a/ipaserver/install/upgradeinstance.py b/ipaserver/install/upgradeinstance.py
index 08d5e91fb41cb395b3599818d3f506374ebad2eb..f70312f0975cc6dad9e637334cc99f6b92c771e9 100644
--- a/ipaserver/install/upgradeinstance.py
+++ b/ipaserver/install/upgradeinstance.py
@@ -17,6 +17,7 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
 
+import ldif
 import os
 import sys
 import shutil
@@ -32,6 +33,116 @@ from ipaserver.install import service
 
 DSE = 'dse.ldif'
 
+
+class GetEntryFromLDIF(ldif.LDIFParser):
+    """
+    LDIF parser.
+    To get results, method parse() must be called first, then method
+    get_results() which return parsed entries
+    """
+    def __init__(self, input_file, entries_dn=[]):
+        """
+        Parse LDIF file.
+        :param input_file: an LDIF file to be parsed
+        :param entries_dn: list of DN which will be returned. All entries are
+         returned if list is empty.
+        """
+        ldif.LDIFParser.__init__(self, input_file)
+        self.entries_dn = entries_dn
+        self.results = {}
+
+    def get_results(self):
+        """
+        Returns results in dictionary {DN: entry, ...}
+        """
+        return self.results
+
+    def handle(self, dn, entry):
+        if self.entries_dn and dn not in self.entries_dn:
+            return
+
+        self.results[dn] = entry
+
+
+class ModifyLDIF(ldif.LDIFParser):
+    """
+    Allows to modify LDIF file.
+
+    Remove operations are executed before add operations
+    """
+    def __init__(self, input_file, writer):
+        """
+        :param input_file: an LDIF
+        :param writer: ldif.LDIFWriter instance where modified LDIF will
+        be written
+        """
+        ldif.LDIFParser.__init__(self, input_file)
+        self.writer = writer
+
+        self.add_dict = {}
+        self.remove_dict = {}
+
+    def add_value(self, dn, attr, value):
+        """
+        Add value to LDIF.
+        :param dn: DN of entry (must exists)
+        :param attr: attribute name
+        :param value: value to be added
+        """
+        attr = attr.lower()
+        entry = self.add_dict.setdefault(dn, {})
+        attribute = entry.setdefault(attr, [])
+        if value not in attribute:
+            attribute.append(value)
+
+    def remove_value(self, dn, attr, value=None):
+        """
+        Remove value from LDIF.
+        :param dn: DN of entry
+        :param attr: attribute name
+        :param value: value to be removed, if value is None, attribute will
+        be removed
+        """
+        attr = attr.lower()
+        entry = self.remove_dict.setdefault(dn, {})
+
+        if entry is None:
+            return
+        attribute = entry.setdefault(attr, [])
+        if value is None:
+            # remove all values
+            entry[attr] = None
+            return
+        elif attribute is None:
+            # already marked to remove all values
+            return
+        if value not in attribute:
+            attribute.append(value)
+
+    def handle(self, dn, entry):
+        if dn in self.remove_dict:
+            for name, value in self.remove_dict[dn].iteritems():
+                if value is None:
+                    attribute = []
+                else:
+                    attribute = entry.setdefault(name, [])
+                    attribute = [v for v in attribute if v not in value]
+                entry[name] = attribute
+
+                if not attribute:  # empty
+                    del entry[name]
+
+        if dn in self.add_dict:
+            for name, value in self.add_dict[dn].iteritems():
+                attribute = entry.setdefault(name, [])
+                attribute.extend([v for v in value if v not in attribute])
+
+        if not entry:  # empty
+            return
+
+        self.writer.unparse(dn, entry)
+
+
 class IPAUpgrade(service.Service):
     """
     Update the LDAP data in an instance by turning off all network
@@ -89,34 +200,68 @@ class IPAUpgrade(service.Service):
 
     def __save_config(self):
         shutil.copy2(self.filename, self.savefilename)
-        port = installutils.get_directive(self.filename, 'nsslapd-port',
-               separator=':')
-        security = installutils.get_directive(self.filename, 'nsslapd-security',
-                   separator=':')
+        with open(self.filename, "rb") as in_file:
+            parser = GetEntryFromLDIF(in_file, entries_dn=["cn=config"])
+            parser.parse()
+            try:
+                config_entry = parser.get_results()["cn=config"]
+            except KeyError:
+                raise RuntimeError("Unable to find cn=config entry in %s" %
+                                   self.filename)
 
-        self.backup_state('nsslapd-port', port)
-        self.backup_state('nsslapd-security', security)
+            try:
+                port = config_entry['nsslapd-port'][0]
+            except KeyError:
+                pass
+            else:
+                self.backup_state('nsslapd-port', port)
+
+            try:
+                security = config_entry['nsslapd-security'][0]
+            except KeyError:
+                pass
+            else:
+                self.backup_state('nsslapd-security', security)
 
     def __restore_config(self):
         port = self.restore_state('nsslapd-port')
         security = self.restore_state('nsslapd-security')
 
-        if port is not None:
-            installutils.set_directive(
-                self.filename, 'nsslapd-port', port,
-                quotes=False, separator=':')
-        if security is not None:
-            installutils.set_directive(
-                self.filename, 'nsslapd-security', security,
-                quotes=False, separator=':')
+        ldif_outfile = "%s.modified.out" % self.filename
+        with open(ldif_outfile, "wb") as out_file:
+            ldif_writer = ldif.LDIFWriter(out_file)
+            with open(self.filename, "rb") as in_file:
+                parser = ModifyLDIF(in_file, ldif_writer)
+
+                if port is not None:
+                    parser.remove_value("cn=config", "nsslapd-port")
+                    parser.add_value("cn=config", "nsslapd-port", port)
+                if security is not None:
+                    parser.remove_value("cn=config", "nsslapd-security")
+                    parser.add_value("cn=config", "nsslapd-security", security)
+
+                parser.parse()
+
+        shutil.copy2(ldif_outfile, self.filename)
 
     def __disable_listeners(self):
-        installutils.set_directive(self.filename, 'nsslapd-port',
-            0, quotes=False, separator=':')
-        installutils.set_directive(self.filename, 'nsslapd-security',
-            'off', quotes=False, separator=':')
-        installutils.set_directive(self.filename, 'nsslapd-ldapientrysearchbase',
-            None, quotes=False, separator=':')
+        ldif_outfile = "%s.modified.out" % self.filename
+        with open(ldif_outfile, "wb") as out_file:
+            ldif_writer = ldif.LDIFWriter(out_file)
+            with open(self.filename, "rb") as in_file:
+                parser = ModifyLDIF(in_file, ldif_writer)
+
+                parser.remove_value("cn=config", "nsslapd-port")
+                parser.add_value("cn=config", "nsslapd-port", "0")
+
+                parser.remove_value("cn=config", "nsslapd-security")
+                parser.add_value("cn=config", "nsslapd-security", "off")
+
+                parser.remove_value("cn=config", "nsslapd-ldapientrysearchbase")
+
+                parser.parse()
+
+        shutil.copy2(ldif_outfile, self.filename)
 
     def __update_schema(self):
         self.modified = schemaupdate.update_schema(
-- 
2.1.0

From 55523cf2483b889ad066b7f4dab7e9e033610648 Mon Sep 17 00:00:00 2001
From: Martin Basti <mba...@redhat.com>
Date: Mon, 27 Apr 2015 10:34:25 +0200
Subject: [PATCH 3/3] Server Upgrade: enable DS global lock during upgrade

https://fedorahosted.org/freeipa/ticket/4925
---
 freeipa.spec.in                      |  6 +++---
 ipaserver/install/dsinstance.py      |  8 +++-----
 ipaserver/install/upgradeinstance.py | 34 +++++++++++++++++++++++++++++++++-
 3 files changed, 39 insertions(+), 9 deletions(-)

diff --git a/freeipa.spec.in b/freeipa.spec.in
index 8b58b0e0525357241ec95ae40b3e7b4b8c6ce118..725a6cfa55a40e688ca7f4ef18268c22fe46c06e 100644
--- a/freeipa.spec.in
+++ b/freeipa.spec.in
@@ -33,7 +33,7 @@ Source0:        freeipa-%{version}.tar.gz
 BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 
 %if ! %{ONLY_CLIENT}
-BuildRequires:  389-ds-base-devel >= 1.3.3.8
+BuildRequires:  389-ds-base-devel >= 1.3.3.9
 BuildRequires:  svrcore-devel
 BuildRequires:  policycoreutils >= 2.1.12-5
 BuildRequires:  systemd-units
@@ -108,7 +108,7 @@ Group: System Environment/Base
 Requires: %{name}-python = %{version}-%{release}
 Requires: %{name}-client = %{version}-%{release}
 Requires: %{name}-admintools = %{version}-%{release}
-Requires: 389-ds-base >= 1.3.3.8
+Requires: 389-ds-base >= 1.3.3.9
 Requires: openldap-clients > 2.4.35-4
 Requires: nss >= 3.14.3-12.0
 Requires: nss-tools >= 3.14.3-12.0
@@ -143,7 +143,7 @@ Requires: zip
 Requires: policycoreutils >= 2.1.12-5
 Requires: tar
 Requires(pre): certmonger >= 0.76.8
-Requires(pre): 389-ds-base >= 1.3.3.8
+Requires(pre): 389-ds-base >= 1.3.3.9
 Requires: fontawesome-fonts
 Requires: open-sans-fonts
 Requires: openssl
diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py
index 52df6b7dea218669f9f89a7f6ae65614f494368c..8da6d14644b2eae3f6fb58fcb9c6e0fe639195fc 100644
--- a/ipaserver/install/dsinstance.py
+++ b/ipaserver/install/dsinstance.py
@@ -36,6 +36,7 @@ import ldap
 from ipaserver.install import ldapupdate
 from ipaserver.install import replication
 from ipaserver.install import sysupgrade
+from ipaserver.install import upgradeinstance
 from ipalib import api
 from ipalib import certstore
 from ipalib import errors
@@ -504,13 +505,10 @@ class DsInstance(service.Service):
         conn.unbind()
 
     def apply_updates(self):
-        ld = ldapupdate.LDAPUpdate(dm_password=self.dm_password,
-                                   sub_dict=self.sub_dict)
-        files = ld.get_all_files(ldapupdate.UPDATES_DIR)
-        ld.update(files)
+        data_upgrade = upgradeinstance.IPAUpgrade(self.realm)
+        data_upgrade.create_instance()
         installutils.store_version()
 
-
     def __add_referint_module(self):
         self._ldap_mod("referint-conf.ldif")
 
diff --git a/ipaserver/install/upgradeinstance.py b/ipaserver/install/upgradeinstance.py
index f70312f0975cc6dad9e637334cc99f6b92c771e9..ddf1688f827db81c9cd01b16919e43323b625b60 100644
--- a/ipaserver/install/upgradeinstance.py
+++ b/ipaserver/install/upgradeinstance.py
@@ -25,6 +25,7 @@ import random
 import traceback
 from ipaplatform.paths import paths
 from ipapython.ipa_log_manager import *
+from ipapython import ipaldap
 
 from ipaserver.install import installutils
 from ipaserver.install import schemaupdate
@@ -170,6 +171,7 @@ class IPAUpgrade(service.Service):
         self.upgradefailed = False
         self.serverid = serverid
         self.schema_files = schema_files
+        self.realm = realm_name
 
     def __start_nowait(self):
         # Don't wait here because we've turned off port 389. The connection
@@ -184,11 +186,11 @@ class IPAUpgrade(service.Service):
         self.step("stopping directory server", self.__stop_instance)
         self.step("saving configuration", self.__save_config)
         self.step("disabling listeners", self.__disable_listeners)
+        self.step("enabling DS global lock", self.__enable_ds_global_write_lock)
         self.step("starting directory server", self.__start_nowait)
         if self.schema_files:
             self.step("updating schema", self.__update_schema)
         self.step("upgrading server", self.__upgrade)
-
         self.step("stopping directory server", self.__stop_instance,
                   run_after_failure=True)
         self.step("restoring configuration", self.__restore_config,
@@ -200,6 +202,7 @@ class IPAUpgrade(service.Service):
 
     def __save_config(self):
         shutil.copy2(self.filename, self.savefilename)
+
         with open(self.filename, "rb") as in_file:
             parser = GetEntryFromLDIF(in_file, entries_dn=["cn=config"])
             parser.parse()
@@ -223,9 +226,31 @@ class IPAUpgrade(service.Service):
             else:
                 self.backup_state('nsslapd-security', security)
 
+            try:
+                global_lock = config_entry['nsslapd-global-backend-lock'][0]
+            except KeyError:
+                pass
+            else:
+                self.backup_state('nsslapd-global-backend-lock', global_lock)
+
+    def __enable_ds_global_write_lock(self):
+        ldif_outfile = "%s.modified.out" % self.filename
+        with open(ldif_outfile, "wb") as out_file:
+            ldif_writer = ldif.LDIFWriter(out_file)
+            with open(self.filename, "rb") as in_file:
+                parser = ModifyLDIF(in_file, ldif_writer)
+
+                parser.remove_value("cn=config", "nsslapd-global-backend-lock")
+                parser.add_value("cn=config", "nsslapd-global-backend-lock",
+                                 "on")
+                parser.parse()
+
+        shutil.copy2(ldif_outfile, self.filename)
+
     def __restore_config(self):
         port = self.restore_state('nsslapd-port')
         security = self.restore_state('nsslapd-security')
+        global_lock = self.restore_state('nsslapd-global-backend-lock')
 
         ldif_outfile = "%s.modified.out" % self.filename
         with open(ldif_outfile, "wb") as out_file:
@@ -240,6 +265,12 @@ class IPAUpgrade(service.Service):
                     parser.remove_value("cn=config", "nsslapd-security")
                     parser.add_value("cn=config", "nsslapd-security", security)
 
+                # disable global lock by default
+                parser.remove_value("cn=config", "nsslapd-global-backend-lock")
+                if global_lock is not None:
+                    parser.add_value("cn=config", "nsslapd-global-backend-lock",
+                                     global_lock)
+
                 parser.parse()
 
         shutil.copy2(ldif_outfile, self.filename)
@@ -285,6 +316,7 @@ class IPAUpgrade(service.Service):
             root_logger.error('Upgrade failed with %s' % str(e))
             root_logger.debug('%s', traceback.format_exc())
 
+
 def main():
     if os.getegid() != 0:
         print "Must be root to set up server"
-- 
2.1.0

-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to