Blob Blame History Raw
From 5d377f31292da71f6ec4a29b13a66a9bea967102 Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata@redhat.com>
Date: Tue, 2 Nov 2021 14:46:02 -0500
Subject: [PATCH] Fix replica reinstallation

The pkispawn and pkidestroy have been modified to ignore
failures caused by adding an entry or attribute that is
already exists and to check whether a file exists before
removing it during replica removal and reinstallation.

One of the CA clone tests has been modified to test
removing and reinstalling a replica.

Resolves: https://github.com/dogtagpki/pki/issues/3544
---
 .github/workflows/ca-tests.yml                |  11 ++
 .../python/pki/server/deployment/__init__.py  |  39 +++++--
 .../scriptlets/webapp_deployment.py           |  19 +--
 .../cms/servlet/csadmin/LDAPConfigurator.java | 110 +++++++++++-------
 4 files changed, 116 insertions(+), 63 deletions(-)

diff --git a/.github/workflows/ca-tests.yml b/.github/workflows/ca-tests.yml
index 4832e73c65..fffcb9c3e4 100644
--- a/.github/workflows/ca-tests.yml
+++ b/.github/workflows/ca-tests.yml
@@ -1137,6 +1137,17 @@ jobs:
               --pkcs12-password-file ${PKIDIR}/pkcs12_password.conf
           docker exec secondary pki -n caadmin ca-user-show caadmin
 
+      - name: Remove CA from secondary PKI container
+        run: |
+          docker exec secondary pkidestroy -i pki-tomcat -s CA -v
+
+      - name: Re-install CA in secondary PKI container
+        run: |
+          docker exec secondary pkispawn \
+              -f /usr/share/pki/server/examples/installation/ca-secure-ds-secondary.cfg \
+              -s CA \
+              -v
+
       - name: Gather artifacts from primary container
         if: always()
         run: |
diff --git a/base/server/python/pki/server/deployment/__init__.py b/base/server/python/pki/server/deployment/__init__.py
index 6eb5b0a78a..d179718dd6 100644
--- a/base/server/python/pki/server/deployment/__init__.py
+++ b/base/server/python/pki/server/deployment/__init__.py
@@ -1074,26 +1074,41 @@ class PKIDeployer:
         secure_port = server_config.get_secure_port()
 
         uid = 'CA-%s-%s' % (self.mdict['pki_hostname'], secure_port)
-
         logger.info('Adding %s', uid)
-        subsystem.add_user(
-            uid,
-            full_name=uid,
-            user_type='agentType',
-            state='1')
 
-        logger.info('Adding subsystem certificate into %s', uid)
+        try:
+            subsystem.add_user(
+                uid,
+                full_name=uid,
+                user_type='agentType',
+                state='1')
+        except Exception:    # pylint: disable=W0703
+            logger.warning('Unable to add %s', uid)
+            # TODO: ignore error only if user already exists
+
         cert_data = pki.nssdb.convert_cert(
             cert['data'],
             'base64',
             'pem')
-        subsystem.add_user_cert(
-            uid,
-            cert_data=cert_data.encode(),
-            cert_format='PEM')
+
+        logger.info('Adding certificate for %s', uid)
+
+        try:
+            subsystem.add_user_cert(
+                uid,
+                cert_data=cert_data.encode(),
+                cert_format='PEM')
+        except Exception:    # pylint: disable=W0703
+            logger.warning('Unable to add certificate for %s', uid)
+            # TODO: ignore error only if user cert already exists
 
         logger.info('Adding %s into Subsystem Group', uid)
-        subsystem.add_group_member('Subsystem Group', uid)
+
+        try:
+            subsystem.add_group_member('Subsystem Group', uid)
+        except Exception:    # pylint: disable=W0703
+            logger.warning('Unable to add %s into Subsystem Group', uid)
+            # TODO: ignore error only if user already exists in the group
 
     def backup_keys(self, instance, subsystem):
 
diff --git a/base/server/python/pki/server/deployment/scriptlets/webapp_deployment.py b/base/server/python/pki/server/deployment/scriptlets/webapp_deployment.py
index 342477028a..f9e73fd069 100644
--- a/base/server/python/pki/server/deployment/scriptlets/webapp_deployment.py
+++ b/base/server/python/pki/server/deployment/scriptlets/webapp_deployment.py
@@ -60,12 +60,13 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
 
         logger.info('Undeploying /%s web application', deployer.mdict['pki_subsystem'].lower())
 
-        # Delete <instance>/Catalina/localhost/<subsystem>.xml
-        pki.util.remove(
-            path=os.path.join(
-                deployer.mdict['pki_instance_configuration_path'],
-                "Catalina",
-                "localhost",
-                deployer.mdict['pki_subsystem'].lower() + ".xml"),
-            force=deployer.mdict['pki_force_destroy']
-        )
+        # Delete <instance>/Catalina/localhost/<subsystem>.xml if exists
+
+        context_xml = os.path.join(
+            deployer.mdict['pki_instance_configuration_path'],
+            'Catalina',
+            'localhost',
+            deployer.mdict['pki_subsystem'].lower() + '.xml')
+
+        if os.path.exists(context_xml):
+            pki.util.remove(context_xml)
diff --git a/base/server/src/main/java/com/netscape/cms/servlet/csadmin/LDAPConfigurator.java b/base/server/src/main/java/com/netscape/cms/servlet/csadmin/LDAPConfigurator.java
index 651d166321..1e0364cfea 100644
--- a/base/server/src/main/java/com/netscape/cms/servlet/csadmin/LDAPConfigurator.java
+++ b/base/server/src/main/java/com/netscape/cms/servlet/csadmin/LDAPConfigurator.java
@@ -661,26 +661,35 @@ public class LDAPConfigurator {
 
         try {
             connection.add(entry);
+            // replication manager added -> done
+            return;
 
         } catch (LDAPException e) {
-            if (e.getLDAPResultCode() == LDAPException.ENTRY_ALREADY_EXISTS) {
-                logger.warn("Entry already exists: " + dn);
+            if (e.getLDAPResultCode() != LDAPException.ENTRY_ALREADY_EXISTS) {
+                logger.error("Unable to add " + dn + ": " + e.getMessage(), e);
+                throw e;
+            }
+            logger.warn("Replication manager already exists: " + dn);
+        }
 
-                try {
-                    logger.info("Deleting " + dn);
-                    connection.delete(dn);
+        logger.warn("Deleting existing replication manager: " + dn);
 
-                    logger.info("Re-adding " + dn);
-                    connection.add(entry);
+        try {
+            connection.delete(dn);
 
-                } catch (LDAPException ee) {
-                    logger.warn("Unable to recreate " + dn + ": " + ee.getMessage());
-                }
+        } catch (LDAPException e) {
+            logger.error("Unable to delete " + dn + ": " + e.getMessage());
+            throw e;
+        }
 
-            } else {
-                logger.error("Unable to add " + dn + ": " + e.getMessage(), e);
-                throw e;
-            }
+        logger.warn("Adding new replication manager: " + dn);
+
+        try {
+            connection.add(entry);
+
+        } catch (LDAPException e) {
+            logger.error("Unable to add " + dn + ": " + e.getMessage());
+            throw e;
         }
     }
 
@@ -799,28 +808,41 @@ public class LDAPConfigurator {
 
         try {
             connection.add(entry);
+            // replica object added -> done
+            return true;
 
         } catch (LDAPException e) {
-
             if (e.getLDAPResultCode() != LDAPException.ENTRY_ALREADY_EXISTS) {
+                logger.error("Unable to add " + replicaDN + ": " + e.getMessage(), e);
                 throw e;
             }
+            logger.warn("Replica object already exists: " + replicaDN);
+        }
+
+        logger.info("Adding replica bind DN");
 
-            // BZ 470918: We can't just add the new dn.
-            // We need to do a replace until the bug is fixed.
-            logger.warn("Entry already exists, adding bind DN");
+        // BZ 470918: We can't just add the new dn.
+        // We need to do a replace until the bug is fixed.
 
-            entry = connection.read(replicaDN);
-            LDAPAttribute attr = entry.getAttribute("nsDS5ReplicaBindDN");
-            attr.addValue(bindDN);
+        entry = connection.read(replicaDN);
+        LDAPAttribute attr = entry.getAttribute("nsDS5ReplicaBindDN");
+        attr.addValue(bindDN);
 
-            LDAPModification mod = new LDAPModification(LDAPModification.REPLACE, attr);
+        LDAPModification mod = new LDAPModification(LDAPModification.REPLACE, attr);
+
+        try {
             connection.modify(replicaDN, mod);
+            // replica bind DN added -> done
 
-            return false;
+        } catch (LDAPException e) {
+            if (e.getLDAPResultCode() != LDAPException.ATTRIBUTE_OR_VALUE_EXISTS) {
+                logger.error("Unable to add " + bindDN + ": " + e.getMessage(), e);
+                throw e;
+            }
+            logger.warn("Replica bind DN already exists: " + bindDN);
         }
 
-        return true;
+        return false;
     }
 
     public void createReplicationAgreement(
@@ -864,29 +886,33 @@ public class LDAPConfigurator {
 
         try {
             connection.add(entry);
+            // replication agreement added -> done
+            return;
 
         } catch (LDAPException e) {
-            if (e.getLDAPResultCode() == LDAPException.ENTRY_ALREADY_EXISTS) {
-                logger.warn("Entry already exists: " + dn);
-
-                try {
-                    connection.delete(dn);
-                } catch (LDAPException ee) {
-                    logger.error("Unable to delete " + dn + ": " + ee.getMessage(), ee);
-                    throw ee;
-                }
-
-                try {
-                    connection.add(entry);
-                } catch (LDAPException ee) {
-                    logger.error("Unable to add " + dn + ": " + ee.getMessage(), ee);
-                    throw ee;
-                }
-
-            } else {
+            if (e.getLDAPResultCode() != LDAPException.ENTRY_ALREADY_EXISTS) {
                 logger.error("Unable to add " + dn + ": " + e.getMessage(), e);
                 throw e;
             }
+            logger.warn("Replication agreement already exists: " + dn);
+        }
+
+        logger.warn("Removing existing replication agreement: " + dn);
+
+        try {
+            connection.delete(dn);
+        } catch (LDAPException e) {
+            logger.error("Unable to delete " + dn + ": " + e.getMessage(), e);
+            throw e;
+        }
+
+        logger.warn("Adding new replication agreement: " + dn);
+
+        try {
+            connection.add(entry);
+        } catch (LDAPException e) {
+            logger.error("Unable to add " + dn + ": " + e.getMessage(), e);
+            throw e;
         }
     }
 
-- 
2.31.1