Browse Source

Ticket 50363 - ds-replcheck incorrectly reports error out of order multi-valued attributes

Bug Description:  If for some reason an entry's multi-valued attribute
                  values are in different orders on different replicas
                  the tool reports this as an inconsistency when it is
                  not.

Fix Description:  For both offline & online processing sort each entry's
                  multi-valued attribute values.

https://pagure.io/389-ds-base/issue/50363

Reviewed by: firstyear & mhonek (Thanks!!)
Mark Reynolds 6 years ago
parent
commit
974c802fce

+ 9 - 0
dirsrvtests/tests/suites/ds_tools/replcheck_test.py

@@ -343,6 +343,8 @@ def test_inconsistencies(topo_tls_ldapi):
     m2 = topo_tls_ldapi.ms["master2"]
     attr_m1 = "m1_inconsistency"
     attr_m2 = "m2_inconsistency"
+    attr_first = "first ordered valued"
+    attr_second = "second ordered valued"
     attr_m1_only = "123123123"
 
     try:
@@ -355,6 +357,9 @@ def test_inconsistencies(topo_tls_ldapi):
         user_m1.set("description", attr_m1)
         user_m2.set("description", attr_m2)
         user_m1.set("telephonenumber", attr_m1_only)
+        # Add the same multi-valued attrs, but out of order
+        user_m1.set("cn", [attr_first, attr_second])
+        user_m2.set("cn", [attr_second, attr_first])
         time.sleep(2)
 
         for tool_cmd in replcheck_cmd_list(topo_tls_ldapi):
@@ -362,12 +367,16 @@ def test_inconsistencies(topo_tls_ldapi):
             assert attr_m1 in result
             assert attr_m2 in result
             assert attr_m1_only in result
+            assert attr_first not in result
+            assert attr_second not in result
             # Ignore some attributes and check the output
             tool_cmd.extend(['-i', '{},{}'.format('description', 'telephonenumber')])
             result = subprocess.check_output(tool_cmd, encoding='utf-8').lower()
             assert attr_m1 not in result
             assert attr_m2 not in result
             assert attr_m1_only not in result
+            assert attr_first not in result
+            assert attr_second not in result
 
     finally:
         topo_tls_ldapi.resume_all_replicas()

+ 6 - 1
ldap/admin/src/scripts/ds-replcheck

@@ -125,7 +125,7 @@ def convert_entries(entries):
 
     for entry in entries:
         new_entry = Entry(entry)
-        new_entry.data = {k.lower(): v for k, v in list(new_entry.data.items())}
+        new_entry.data = {k.lower(): sorted(v) for k, v in list(new_entry.data.items())}
 
         # Decode nscpentrywsi bytes values for future use
         nscpentrywsi_list = []
@@ -448,6 +448,11 @@ def ldif_search(LDIF, dn):
     # Keep track of entry index - we use this later when searching the LDIF again
     result['idx'] = count
 
+    # Sort all the multi-valued attributes
+    for k, v in data.items():
+        v.sort()
+        data[k] = v
+
     result['glue'] = None
     if found_conflict and found_subentry and found_tombstone is False:
         result['entry'] = None