Blame SOURCES/0003-Ticket-49840-ds-replcheck-command-returns-traceback-.patch

31affc
From 6361810037bc32c22e3e00a16bc53b34d0b0d610 Mon Sep 17 00:00:00 2001
31affc
From: Mark Reynolds <mreynolds@redhat.com>
31affc
Date: Mon, 9 Jul 2018 15:50:09 -0400
31affc
Subject: [PATCH] Ticket 49840 - ds-replcheck command returns traceback errors
31affc
 against ldif files having garbage content when run in offline mode
31affc
31affc
Description:  Added a basic check to see if the LDIF files are actually
31affc
              LDIF files.  Also added checks that the database RUV are
31affc
              present as well.
31affc
31affc
https://pagure.io/389-ds-base/issue/49840
31affc
31affc
Reviewed by: spichugi(Thanks!)
31affc
31affc
(cherry picked from commit 60cb52040704686d9541a2e2eb2765d86cb10af2)
31affc
---
31affc
 ldap/admin/src/scripts/ds-replcheck | 53 +++++++++++++++++++++++------
31affc
 1 file changed, 43 insertions(+), 10 deletions(-)
31affc
31affc
diff --git a/ldap/admin/src/scripts/ds-replcheck b/ldap/admin/src/scripts/ds-replcheck
31affc
index 62f911034..5c195f983 100755
31affc
--- a/ldap/admin/src/scripts/ds-replcheck
31affc
+++ b/ldap/admin/src/scripts/ds-replcheck
31affc
@@ -10,18 +10,19 @@
31affc
 #
31affc
 
31affc
 import os
31affc
+import sys
31affc
 import re
31affc
 import time
31affc
 import ldap
31affc
 import ldapurl
31affc
 import argparse
31affc
 import getpass
31affc
-
31affc
+from ldif import LDIFRecordList
31affc
 from ldap.ldapobject import SimpleLDAPObject
31affc
 from ldap.cidict import cidict
31affc
 from ldap.controls import SimplePagedResultsControl
31affc
 
31affc
-VERSION = "1.3"
31affc
+VERSION = "1.4"
31affc
 RUV_FILTER = '(&(nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff)(objectclass=nstombstone))'
31affc
 LDAP = 'ldap'
31affc
 LDAPS = 'ldaps'
31affc
@@ -386,14 +387,17 @@ def ldif_search(LDIF, dn):
31affc
     return result
31affc
 
31affc
 
31affc
-def get_dns(LDIF, opts):
31affc
+def get_dns(LDIF, filename, opts):
31affc
     ''' Get all the DN's from an LDIF file
31affc
     '''
31affc
     dns = []
31affc
     found = False
31affc
+    found_ruv = False
31affc
+    LDIF.seek(0)
31affc
     for line in LDIF:
31affc
         if line.startswith('dn: ') and line[4:].startswith('nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff'):
31affc
             opts['ruv_dn'] = line[4:].lower().strip()
31affc
+            found_ruv = True
31affc
         elif line.startswith('dn: '):
31affc
             found = True
31affc
             dn = line[4:].lower().strip()
31affc
@@ -407,6 +411,14 @@ def get_dns(LDIF, opts):
31affc
             found = False
31affc
             dns.append(dn)
31affc
 
31affc
+    if not found_ruv:
31affc
+        print('Failed to find the database RUV in the LDIF file: ' + filename + ', the LDIF ' +
31affc
+              'file must contain replication state information.')
31affc
+        dns = None
31affc
+    else:
31affc
+        # All good, reset cursor
31affc
+        LDIF.seek(0)
31affc
+
31affc
     return dns
31affc
 
31affc
 
31affc
@@ -415,6 +427,7 @@ def get_ldif_ruv(LDIF, opts):
31affc
     '''
31affc
     LDIF.seek(0)
31affc
     result = ldif_search(LDIF, opts['ruv_dn'])
31affc
+    LDIF.seek(0)  # Reset cursor
31affc
     return result['entry'].data['nsds50ruv']
31affc
 
31affc
 
31affc
@@ -549,6 +562,7 @@ def do_offline_report(opts, output_file=None):
31affc
     rconflicts = []
31affc
     rtombstones = 0
31affc
     mtombstones = 0
31affc
+    idx = 0
31affc
 
31affc
     # Open LDIF files
31affc
     try:
31affc
@@ -561,12 +575,36 @@ def do_offline_report(opts, output_file=None):
31affc
         RLDIF = open(opts['rldif'], "r")
31affc
     except Exception as e:
31affc
         print('Failed to open Replica LDIF: ' + str(e))
31affc
+        MLDIF.close()
31affc
+        return None
31affc
+
31affc
+    # Verify LDIF Files
31affc
+    try:
31affc
+        print("Validating Master ldif file ({})...".format(opts['mldif']))
31affc
+        LDIFRecordList(MLDIF).parse()
31affc
+    except ValueError:
31affc
+        print('Master LDIF file in invalid, aborting...')
31affc
+        MLDIF.close()
31affc
+        RLDIF.close()
31affc
+        return None
31affc
+    try:
31affc
+        print("Validating Replica ldif file ({})...".format(opts['rldif']))
31affc
+        LDIFRecordList(RLDIF).parse()
31affc
+    except ValueError:
31affc
+        print('Replica LDIF file is invalid, aborting...')
31affc
+        MLDIF.close()
31affc
+        RLDIF.close()
31affc
         return None
31affc
 
31affc
     # Get all the dn's, and entry counts
31affc
     print ("Gathering all the DN's...")
31affc
-    master_dns = get_dns(MLDIF, opts)
31affc
-    replica_dns = get_dns(RLDIF, opts)
31affc
+    master_dns = get_dns(MLDIF, opts['mldif'], opts)
31affc
+    replica_dns = get_dns(RLDIF, opts['rldif'], opts)
31affc
+    if master_dns is None or replica_dns is None:
31affc
+        print("Aborting scan...")
31affc
+        MLDIF.close()
31affc
+        RLDIF.close()
31affc
+        sys.exit(1)
31affc
     m_count = len(master_dns)
31affc
     r_count = len(replica_dns)
31affc
 
31affc
@@ -575,11 +613,6 @@ def do_offline_report(opts, output_file=None):
31affc
     opts['master_ruv'] = get_ldif_ruv(MLDIF, opts)
31affc
     opts['replica_ruv'] = get_ldif_ruv(RLDIF, opts)
31affc
 
31affc
-    # Reset the cursors
31affc
-    idx = 0
31affc
-    MLDIF.seek(idx)
31affc
-    RLDIF.seek(idx)
31affc
-
31affc
     """ Compare the master entries with the replica's.  Take our list of dn's from
31affc
     the master ldif and get that entry( dn) from the master and replica ldif.  In
31affc
     this phase we keep keep track of conflict/tombstone counts, and we check for
31affc
-- 
31affc
2.17.1
31affc