Blame SOURCES/0001-Issue-50525-nsslapd-defaultnamingcontext-does-not-ch.patch

4c04d8
From d33743c8604ff4f97947dad14fddab0691e3d19e Mon Sep 17 00:00:00 2001
4c04d8
From: Mark Reynolds <mreynolds@redhat.com>
4c04d8
Date: Thu, 1 Aug 2019 16:50:34 -0400
4c04d8
Subject: [PATCH] Issue 50525 - nsslapd-defaultnamingcontext does not change
4c04d8
 when the assigned suffix gets deleted
4c04d8
4c04d8
Bug Description:
4c04d8
4c04d8
If you delete the suffix that is set as the default naming context, the attribute
4c04d8
is not reset.
4c04d8
4c04d8
Also using dsconf to delete a backend/suffix fails if there are vlv indexes, encrypted
4c04d8
attributes, or replication is configured.
4c04d8
4c04d8
Fix Description:
4c04d8
4c04d8
As for the default naming context, if there is a second suffix configured, it will be
4c04d8
automatically set as the new default naming context, otherwise the attribute is not
4c04d8
modified.
4c04d8
4c04d8
For dsconf backend delete issue, it now checks and removes replication configuration
4c04d8
and agreements, and removes all the child entries under the backend entry.
4c04d8
4c04d8
relates: https://pagure.io/389-ds-base/issue/50525
4c04d8
4c04d8
Reviewed by: spichugi(Thanks!)
4c04d8
---
4c04d8
 .../be_del_and_default_naming_attr_test.py    | 90 +++++++++++++++++++
4c04d8
 ldap/servers/slapd/mapping_tree.c             | 50 ++++++-----
4c04d8
 src/lib389/lib389/backend.py                  | 17 ++--
4c04d8
 src/lib389/lib389/replica.py                  |  2 +-
4c04d8
 4 files changed, 132 insertions(+), 27 deletions(-)
4c04d8
 create mode 100644 dirsrvtests/tests/suites/mapping_tree/be_del_and_default_naming_attr_test.py
4c04d8
4c04d8
diff --git a/dirsrvtests/tests/suites/mapping_tree/be_del_and_default_naming_attr_test.py b/dirsrvtests/tests/suites/mapping_tree/be_del_and_default_naming_attr_test.py
4c04d8
new file mode 100644
4c04d8
index 000000000..34a2de2ad
4c04d8
--- /dev/null
4c04d8
+++ b/dirsrvtests/tests/suites/mapping_tree/be_del_and_default_naming_attr_test.py
4c04d8
@@ -0,0 +1,90 @@
4c04d8
+import logging
4c04d8
+import pytest
4c04d8
+import os
4c04d8
+from lib389._constants import DEFAULT_SUFFIX
4c04d8
+from lib389.topologies import topology_m1 as topo
4c04d8
+from lib389.backend import Backends
4c04d8
+from lib389.encrypted_attributes import EncryptedAttrs
4c04d8
+
4c04d8
+DEBUGGING = os.getenv("DEBUGGING", default=False)
4c04d8
+if DEBUGGING:
4c04d8
+    logging.getLogger(__name__).setLevel(logging.DEBUG)
4c04d8
+else:
4c04d8
+    logging.getLogger(__name__).setLevel(logging.INFO)
4c04d8
+log = logging.getLogger(__name__)
4c04d8
+
4c04d8
+SECOND_SUFFIX = 'o=namingcontext'
4c04d8
+THIRD_SUFFIX = 'o=namingcontext2'
4c04d8
+
4c04d8
+def test_be_delete(topo):
4c04d8
+    """Test that we can delete a backend that contains replication
4c04d8
+    configuration and encrypted attributes.  The default naming 
4c04d8
+    context should also be updated to reflect the next available suffix
4c04d8
+
4c04d8
+    :id: 5208f897-7c95-4925-bad0-9ceb95fee678
4c04d8
+    :setup: Master Instance
4c04d8
+    :steps:
4c04d8
+        1. Create second backend/suffix
4c04d8
+        2. Add an encrypted attribute to the default suffix
4c04d8
+        2. Delete default suffix
4c04d8
+        3. Check the nsslapd-defaultnamingcontext is updated
4c04d8
+        4. Delete the last backend
4c04d8
+        5. Check the namingcontext has not changed
4c04d8
+        6. Add new backend
4c04d8
+        7. Set default naming context
4c04d8
+        8. Verify the naming context is correct
4c04d8
+    :expectedresults:
4c04d8
+        1. Success
4c04d8
+        2. Success
4c04d8
+        3. Success
4c04d8
+        4. Success
4c04d8
+        5. Success
4c04d8
+        6. Success
4c04d8
+        7. Success
4c04d8
+        8. Success
4c04d8
+    """
4c04d8
+    
4c04d8
+    inst = topo.ms["master1"] 
4c04d8
+    
4c04d8
+    # Create second suffix      
4c04d8
+    backends = Backends(inst)
4c04d8
+    default_backend = backends.get(DEFAULT_SUFFIX)
4c04d8
+    new_backend = backends.create(properties={'nsslapd-suffix': SECOND_SUFFIX,
4c04d8
+                                              'name': 'namingRoot'})
4c04d8
+  
4c04d8
+    # Add encrypted attribute entry under default suffix
4c04d8
+    encrypt_attrs = EncryptedAttrs(inst, basedn='cn=encrypted attributes,{}'.format(default_backend.dn))
4c04d8
+    encrypt_attrs.create(properties={'cn': 'employeeNumber', 'nsEncryptionAlgorithm': 'AES'})
4c04d8
+    
4c04d8
+    # Delete default suffix
4c04d8
+    default_backend.delete()
4c04d8
+    
4c04d8
+    # Check that the default naming context is set to the new/second suffix
4c04d8
+    default_naming_ctx = inst.config.get_attr_val_utf8('nsslapd-defaultnamingcontext')
4c04d8
+    assert default_naming_ctx == SECOND_SUFFIX
4c04d8
+
4c04d8
+    # delete new backend, but the naming context should not change
4c04d8
+    new_backend.delete()
4c04d8
+
4c04d8
+    # Check that the default naming context is still set to the new/second suffix
4c04d8
+    default_naming_ctx = inst.config.get_attr_val_utf8('nsslapd-defaultnamingcontext')
4c04d8
+    assert default_naming_ctx == SECOND_SUFFIX
4c04d8
+
4c04d8
+    # Add new backend
4c04d8
+    new_backend = backends.create(properties={'nsslapd-suffix': THIRD_SUFFIX,
4c04d8
+                                              'name': 'namingRoot2'})
4c04d8
+
4c04d8
+    # manaully set naming context
4c04d8
+    inst.config.set('nsslapd-defaultnamingcontext', THIRD_SUFFIX)
4c04d8
+
4c04d8
+    # Verify naming context is correct
4c04d8
+    default_naming_ctx = inst.config.get_attr_val_utf8('nsslapd-defaultnamingcontext')
4c04d8
+    assert default_naming_ctx == THIRD_SUFFIX
4c04d8
+
4c04d8
+
4c04d8
+if __name__ == '__main__':
4c04d8
+    # Run isolated
4c04d8
+    # -s for DEBUG mode
4c04d8
+    CURRENT_FILE = os.path.realpath(__file__)
4c04d8
+    pytest.main(["-s", CURRENT_FILE])
4c04d8
+
4c04d8
diff --git a/ldap/servers/slapd/mapping_tree.c b/ldap/servers/slapd/mapping_tree.c
4c04d8
index 834949a67..25e9fb80c 100644
4c04d8
--- a/ldap/servers/slapd/mapping_tree.c
4c04d8
+++ b/ldap/servers/slapd/mapping_tree.c
4c04d8
@@ -1521,26 +1521,36 @@ done:
4c04d8
                 strcpy_unescape_value(escaped, suffix);
4c04d8
             }
4c04d8
             if (escaped && (0 == strcasecmp(escaped, default_naming_context))) {
4c04d8
-                int rc = _mtn_update_config_param(LDAP_MOD_DELETE,
4c04d8
-                                                  CONFIG_DEFAULT_NAMING_CONTEXT,
4c04d8
-                                                  NULL);
4c04d8
-                if (rc) {
4c04d8
-                    slapi_log_err(SLAPI_LOG_ERR,
4c04d8
-                                  "mapping_tree_entry_delete_callback",
4c04d8
-                                  "deleting config param %s failed: RC=%d\n",
4c04d8
-                                  CONFIG_DEFAULT_NAMING_CONTEXT, rc);
4c04d8
-                }
4c04d8
-                if (LDAP_SUCCESS == rc) {
4c04d8
-                    char errorbuf[SLAPI_DSE_RETURNTEXT_SIZE] = {0};
4c04d8
-                    /* Removing defaultNamingContext from cn=config entry
4c04d8
-                     * was successful.  The remove does not reset the
4c04d8
-                     * global parameter.  We need to reset it separately. */
4c04d8
-                    if (config_set_default_naming_context(
4c04d8
-                            CONFIG_DEFAULT_NAMING_CONTEXT,
4c04d8
-                            NULL, errorbuf, CONFIG_APPLY)) {
4c04d8
-                        slapi_log_err(SLAPI_LOG_ERR, "mapping_tree_entry_delete_callback",
4c04d8
-                                      "Setting NULL to %s failed. %s\n",
4c04d8
-                                      CONFIG_DEFAULT_NAMING_CONTEXT, errorbuf);
4c04d8
+                /*
4c04d8
+                 * We can not delete the default naming attribute, so instead
4c04d8
+                 * replace it only if there is another suffix available
4c04d8
+                 */
4c04d8
+                void *node = NULL;
4c04d8
+                Slapi_DN *sdn;
4c04d8
+                sdn = slapi_get_first_suffix(&node, 0);
4c04d8
+                if (sdn) {
4c04d8
+                    char *replacement_suffix = (char *)slapi_sdn_get_dn(sdn);
4c04d8
+                    int rc = _mtn_update_config_param(LDAP_MOD_REPLACE,
4c04d8
+                                                      CONFIG_DEFAULT_NAMING_CONTEXT,
4c04d8
+                                                      replacement_suffix);
4c04d8
+                    if (rc) {
4c04d8
+                        slapi_log_err(SLAPI_LOG_ERR,
4c04d8
+                                      "mapping_tree_entry_delete_callback",
4c04d8
+                                      "replacing config param %s failed: RC=%d\n",
4c04d8
+                                      CONFIG_DEFAULT_NAMING_CONTEXT, rc);
4c04d8
+                    }
4c04d8
+                    if (LDAP_SUCCESS == rc) {
4c04d8
+                        char errorbuf[SLAPI_DSE_RETURNTEXT_SIZE] = {0};
4c04d8
+                        /* Replacing defaultNamingContext from cn=config entry
4c04d8
+                         * was successful.  The replace does not reset the
4c04d8
+                         * global parameter.  We need to reset it separately. */
4c04d8
+                        if (config_set_default_naming_context(
4c04d8
+                                CONFIG_DEFAULT_NAMING_CONTEXT,
4c04d8
+                                replacement_suffix, errorbuf, CONFIG_APPLY)) {
4c04d8
+                            slapi_log_err(SLAPI_LOG_ERR, "mapping_tree_entry_delete_callback",
4c04d8
+                                          "Setting %s tp %s failed. %s\n",
4c04d8
+                                          CONFIG_DEFAULT_NAMING_CONTEXT, replacement_suffix, errorbuf);
4c04d8
+                        }
4c04d8
                     }
4c04d8
                 }
4c04d8
             }
4c04d8
diff --git a/src/lib389/lib389/backend.py b/src/lib389/lib389/backend.py
4c04d8
index 6f4c8694e..4d32038f6 100644
4c04d8
--- a/src/lib389/lib389/backend.py
4c04d8
+++ b/src/lib389/lib389/backend.py
4c04d8
@@ -17,6 +17,7 @@ from lib389 import Entry
4c04d8
 from lib389._mapped_object import DSLdapObjects, DSLdapObject
4c04d8
 from lib389.mappingTree import MappingTrees, MappingTree
4c04d8
 from lib389.exceptions import NoSuchEntryError, InvalidArgumentError
4c04d8
+from lib389.replica import Replicas
4c04d8
 
4c04d8
 # We need to be a factor to the backend monitor
4c04d8
 from lib389.monitor import MonitorBackend
4c04d8
@@ -507,20 +508,24 @@ class Backend(DSLdapObject):
4c04d8
             mt = self._mts.get(selector=bename)
4c04d8
             # Assert the type is "backend"
4c04d8
             # Are these the right types....?
4c04d8
-            if mt.get_attr_val('nsslapd-state') != ensure_bytes('backend'):
4c04d8
+            if mt.get_attr_val('nsslapd-state').lower() != ensure_bytes('backend'):
4c04d8
                 raise ldap.UNWILLING_TO_PERFORM('Can not delete the mapping tree, not for a backend! You may need to delete this backend via cn=config .... ;_; ')
4c04d8
+
4c04d8
+            # Delete replicas first
4c04d8
+            try:
4c04d8
+                Replicas(self._instance).get(mt.get_attr_val_utf8('cn')).delete()
4c04d8
+            except ldap.NO_SUCH_OBJECT:
4c04d8
+                # No replica, no problem
4c04d8
+                pass
4c04d8
+
4c04d8
             # Delete our mapping tree if it exists.
4c04d8
             mt.delete()
4c04d8
         except ldap.NO_SUCH_OBJECT:
4c04d8
             # Righto, it's already gone! Do nothing ...
4c04d8
             pass
4c04d8
-        # Delete all our related indices
4c04d8
-        self._instance.index.delete_all(bename)
4c04d8
 
4c04d8
         # Now remove our children, this is all ldbm config
4c04d8
-        self._instance.delete_branch_s(self._dn, ldap.SCOPE_ONELEVEL)
4c04d8
-        # The super will actually delete ourselves.
4c04d8
-        super(Backend, self).delete()
4c04d8
+        self._instance.delete_branch_s(self._dn, ldap.SCOPE_SUBTREE)
4c04d8
 
4c04d8
     def _lint_mappingtree(self):
4c04d8
         """Backend lint
4c04d8
diff --git a/src/lib389/lib389/replica.py b/src/lib389/lib389/replica.py
4c04d8
index cdd0a9729..7b45683d9 100644
4c04d8
--- a/src/lib389/lib389/replica.py
4c04d8
+++ b/src/lib389/lib389/replica.py
4c04d8
@@ -458,7 +458,7 @@ class ReplicaLegacy(object):
4c04d8
         try:
4c04d8
             self.deleteAgreements(nsuffix)
4c04d8
         except ldap.LDAPError as e:
4c04d8
-            self.log.fatal('Failed to delete replica agreements!')
4c04d8
+            self.log.fatal('Failed to delete replica agreements!  ' + str(e))
4c04d8
             raise
4c04d8
 
4c04d8
         # Delete the replica
4c04d8
-- 
4c04d8
2.21.0
4c04d8