Blame SOURCES/0023-Ticket-49623-cont-cenotaph-errors-on-modrdn-operatio.patch

e52775
From 819eaedc4bd51d0ec34928c5443a7cd7f094c60a Mon Sep 17 00:00:00 2001
e52775
From: Ludwig Krispenz <lkrispen@redhat.com>
e52775
Date: Tue, 11 Feb 2020 09:47:45 +0100
e52775
Subject: [PATCH 1/2] Ticket - 49623-cont cenotaph errors on modrdn operations
e52775
e52775
Bug: In modrdn operations a cenotaph entries are created to track the time when
e52775
	an entry had existed. But in cases where rentries were renamed in cycles
e52775
	reusing the dns again and again this failed with an error: "faild to add cenotaph"
e52775
e52775
Fix: Previous versions of cenotaphs with the same dn are not used (or maybe in very unlikely
e52775
	scenarios) so there is no need to change the dn construction to be able to keep all
e52775
	versions of the same cenotaph. Instead, if the creation of the cenotaph fails because
e52775
	it already exists, the existin cenotaph is moodified with the lifespan data of the
e52775
	cenotaph that was tried to add.
e52775
e52775
Reviewed by: Thierry, thanks
e52775
---
e52775
 .../tests/tickets/ticket49623_2_test.py       | 66 +++++++++++++++++++
e52775
 ldap/servers/plugins/replication/urp.c        | 42 ++++++++++--
e52775
 2 files changed, 104 insertions(+), 4 deletions(-)
e52775
 create mode 100644 dirsrvtests/tests/tickets/ticket49623_2_test.py
e52775
e52775
diff --git a/dirsrvtests/tests/tickets/ticket49623_2_test.py b/dirsrvtests/tests/tickets/ticket49623_2_test.py
e52775
new file mode 100644
e52775
index 000000000..1d3167d49
e52775
--- /dev/null
e52775
+++ b/dirsrvtests/tests/tickets/ticket49623_2_test.py
e52775
@@ -0,0 +1,66 @@
e52775
+# --- BEGIN COPYRIGHT BLOCK ---
e52775
+# Copyright (C) 2020 Red Hat, Inc.
e52775
+# All rights reserved.
e52775
+#
e52775
+# License: GPL (version 3 or any later version).
e52775
+# See LICENSE for details.
e52775
+# --- END COPYRIGHT BLOCK ---
e52775
+#
e52775
+import os
e52775
+import ldap
e52775
+import pytest
e52775
+import subprocess
e52775
+from lib389.tasks import *
e52775
+from lib389.utils import *
e52775
+from lib389.topologies import topology_m1
e52775
+from lib389.idm.user import UserAccounts
e52775
+from lib389._constants import DEFAULT_SUFFIX
e52775
+from contextlib import contextmanager
e52775
+
e52775
+pytestmark = pytest.mark.tier1
e52775
+
e52775
+logging.getLogger(__name__).setLevel(logging.DEBUG)
e52775
+log = logging.getLogger(__name__)
e52775
+
e52775
+
e52775
+@pytest.mark.ds49623
e52775
+@pytest.mark.bz1790986
e52775
+def test_modrdn_loop(topology_m1):
e52775
+    """Test that renaming the same entry multiple times reusing the same
e52775
+       RDN multiple times does not result in cenotaph error messages
e52775
+
e52775
+    :id: 631b2be9-5c03-44c7-9853-a87c923d5b30
e52775
+
e52775
+    :setup: Single master instance
e52775
+
e52775
+    :steps: 1. Add an entry with RDN start rdn
e52775
+            2. Rename the entry to rdn change
e52775
+            3. Rename the entry to start again
e52775
+            4. Rename the entry to rdn change
e52775
+            5. check for cenotaph error messages
e52775
+    :expectedresults:
e52775
+            1. No error messages
e52775
+    """
e52775
+
e52775
+    topo = topology_m1.ms['master1']
e52775
+    TEST_ENTRY_RDN_START = 'start'
e52775
+    TEST_ENTRY_RDN_CHANGE = 'change'
e52775
+    TEST_ENTRY_NAME = 'tuser'
e52775
+    users = UserAccounts(topo, DEFAULT_SUFFIX)
e52775
+    user_properties = {
e52775
+        'uid': TEST_ENTRY_RDN_START,
e52775
+        'cn': TEST_ENTRY_NAME,
e52775
+        'sn': TEST_ENTRY_NAME,
e52775
+        'uidNumber': '1001',
e52775
+        'gidNumber': '2001',
e52775
+        'homeDirectory': '/home/{}'.format(TEST_ENTRY_NAME)
e52775
+    }
e52775
+
e52775
+    tuser = users.create(properties=user_properties)
e52775
+    tuser.rename('uid={}'.format(TEST_ENTRY_RDN_CHANGE), newsuperior=None, deloldrdn=True)
e52775
+    tuser.rename('uid={}'.format(TEST_ENTRY_RDN_START), newsuperior=None, deloldrdn=True)
e52775
+    tuser.rename('uid={}'.format(TEST_ENTRY_RDN_CHANGE), newsuperior=None, deloldrdn=True)
e52775
+
e52775
+    log.info("Check the log messages for cenotaph error")
e52775
+    error_msg = ".*urp_fixup_add_cenotaph - failed to add cenotaph, err= 68"
e52775
+    assert not topo.ds_error_log.match(error_msg)
e52775
diff --git a/ldap/servers/plugins/replication/urp.c b/ldap/servers/plugins/replication/urp.c
e52775
index 37fe77379..d71e1fa63 100644
e52775
--- a/ldap/servers/plugins/replication/urp.c
e52775
+++ b/ldap/servers/plugins/replication/urp.c
e52775
@@ -854,7 +854,7 @@ urp_post_delete_operation(Slapi_PBlock *pb)
e52775
 }
e52775
 
e52775
 static int
e52775
-urp_fixup_add_cenotaph (Slapi_PBlock *pb, char *sessionid, CSN *opcsn)
e52775
+urp_fixup_add_cenotaph(Slapi_PBlock *pb, char *sessionid, CSN *opcsn)
e52775
 {
e52775
     Slapi_PBlock *add_pb;
e52775
     Slapi_Entry *cenotaph = NULL;
e52775
@@ -892,7 +892,7 @@ urp_fixup_add_cenotaph (Slapi_PBlock *pb, char *sessionid, CSN *opcsn)
e52775
     /* slapi_sdn_free(&pre_sdn); */
e52775
 
e52775
     cenotaph = slapi_entry_alloc();
e52775
-    slapi_entry_init(cenotaph, newdn, NULL);
e52775
+    slapi_entry_init(cenotaph, slapi_ch_strdup(newdn), NULL);
e52775
 
e52775
     dncsn = (CSN *)entry_get_dncsn (pre_entry);
e52775
     slapi_entry_add_string(cenotaph, SLAPI_ATTR_OBJECTCLASS, "extensibleobject");
e52775
@@ -914,12 +914,46 @@ urp_fixup_add_cenotaph (Slapi_PBlock *pb, char *sessionid, CSN *opcsn)
e52775
                                     OP_FLAG_REPL_FIXUP|OP_FLAG_NOOP|OP_FLAG_CENOTAPH_ENTRY|SLAPI_OP_FLAG_BYPASS_REFERRALS);
e52775
     slapi_add_internal_pb(add_pb);
e52775
     slapi_pblock_get(add_pb, SLAPI_PLUGIN_INTOP_RESULT, &ret);
e52775
+    slapi_pblock_destroy(add_pb);
e52775
+
e52775
+    if (ret == LDAP_ALREADY_EXISTS) {
e52775
+        /* the cenotaph already exists, probably because of a loop
e52775
+         * in renaming entries. Update it with new csns
e52775
+         */
e52775
+        slapi_log_err(SLAPI_LOG_REPL, sessionid,
e52775
+                       "urp_fixup_add_cenotaph - cenotaph (%s) already exists, updating\n", newdn);
e52775
+        Slapi_PBlock *mod_pb = slapi_pblock_new();
e52775
+        Slapi_Mods smods;
e52775
+        Slapi_DN *sdn = slapi_sdn_new_dn_byval(newdn);
e52775
+        slapi_mods_init(&smods, 4);
e52775
+        slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "cenotaphfrom", csn_as_string(dncsn, PR_FALSE, csnstr));
e52775
+        slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "cenotaphto", csn_as_string(opcsn, PR_FALSE, csnstr));
e52775
+        slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "nstombstonecsn", csn_as_string(opcsn, PR_FALSE, csnstr));
e52775
+
e52775
+        slapi_modify_internal_set_pb_ext(
e52775
+            mod_pb,
e52775
+            sdn,
e52775
+            slapi_mods_get_ldapmods_byref(&smods),
e52775
+            NULL, /* Controls */
e52775
+            NULL,
e52775
+            repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION),
e52775
+            OP_FLAG_REPL_FIXUP|OP_FLAG_NOOP|OP_FLAG_CENOTAPH_ENTRY|SLAPI_OP_FLAG_BYPASS_REFERRALS);
e52775
+
e52775
+        slapi_modify_internal_pb(mod_pb);
e52775
+        slapi_pblock_get(mod_pb, SLAPI_PLUGIN_INTOP_RESULT, &ret);
e52775
+        if (ret != LDAP_SUCCESS) {
e52775
+            slapi_log_err(SLAPI_LOG_ERR, sessionid,
e52775
+                       "urp_fixup_add_cenotaph - failed to modify cenotaph, err= %d\n", ret);
e52775
+        }
e52775
+        slapi_mods_done(&smods);
e52775
+        slapi_sdn_free(&sdn);
e52775
+        slapi_pblock_destroy(mod_pb);
e52775
 
e52775
-    if (ret != LDAP_SUCCESS) {
e52775
+    } else if (ret != LDAP_SUCCESS) {
e52775
         slapi_log_err(SLAPI_LOG_ERR, sessionid,
e52775
                        "urp_fixup_add_cenotaph - failed to add cenotaph, err= %d\n", ret);
e52775
     }
e52775
-    slapi_pblock_destroy(add_pb);
e52775
+    slapi_ch_free_string(&newdn);
e52775
 
e52775
     return ret;
e52775
 }
e52775
-- 
e52775
2.25.1
e52775