|
|
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 |
|